// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use std::collections::HashMap;
use tauri::Manager;
use tauri_plugin_libsql::*;

// 基本命令 - 简单的字符串返回
#[tauri::command]
fn greet(name: &str) -> String {
    format!("Hello, {}! Welcome to the LibSQL example app!", name)
}

// 使用插件 API 的实用指令
#[tauri::command]
async fn create_demo_db(app_handle: tauri::AppHandle) -> Result<String, String> {
    // 连接到 LibSQL 数据库
    let connection_id = app_handle
        .libsql()
        .connect(ConnectOptions {
            local_path: "./demo.db".to_string(),
            url: None,
            auth_token: None,
        })
        .await
        .map_err(|e| e.to_string())?;

    // 创建用户表
    app_handle
        .libsql()
        .execute(ExecuteOptions {
            connection_id: connection_id.clone(),
            sql:
                "CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)"
                    .to_string(),
            params: None,
            named_params: None,
        })
        .await
        .map_err(|e| e.to_string())?;

    // 使用位置参数插入数据
    app_handle
        .libsql()
        .execute(ExecuteOptions {
            connection_id: connection_id.clone(),
            sql: "INSERT INTO users (name, age) VALUES (?, ?)".to_string(),
            params: Some(vec![Value::Text("Alice".to_string()), Value::Integer(30)]),
            named_params: None,
        })
        .await
        .map_err(|e| e.to_string())?;

    // 使用命名参数插入数据
    let mut named_params = HashMap::new();
    named_params.insert(":name".to_string(), Value::Text("Bob".to_string()));
    named_params.insert(":age".to_string(), Value::Integer(25));

    app_handle
        .libsql()
        .execute(ExecuteOptions {
            connection_id: connection_id.clone(),
            sql: "INSERT INTO users (name, age) VALUES (:name, :age)".to_string(),
            params: None,
            named_params: Some(named_params),
        })
        .await
        .map_err(|e| e.to_string())?;

    Ok(format!(
        "Demo database created successfully with connection ID: {}",
        connection_id
    ))
}

// Vector/Embeddings demo
#[tauri::command]
async fn create_vector_demo(app_handle: tauri::AppHandle) -> Result<String, String> {
    // 连接到 LibSQL 数据库
    let connection_id = app_handle
        .libsql()
        .connect(ConnectOptions {
            local_path: "./vector_demo.db".to_string(),
            url: None,
            auth_token: None,
        })
        .await
        .map_err(|e| e.to_string())?;

    // 创建电影表，包含向量列
    app_handle
        .libsql()
        .execute(ExecuteOptions {
            connection_id: connection_id.clone(),
            sql: "CREATE TABLE IF NOT EXISTS movies (
                id INTEGER PRIMARY KEY,
                title TEXT,
                year INTEGER,
                embedding F32_BLOB(4)
            )"
            .to_string(),
            params: None,
            named_params: None,
        })
        .await
        .map_err(|e| e.to_string())?;

    // 插入电影数据，使用 vector32 函数
    let movies = vec![
        ("Napoleon", 2023, vec![0.800, 0.579, 0.481, 0.229]),
        ("Black Hawk Down", 2001, vec![0.406, 0.027, 0.378, 0.056]),
        ("Gladiator", 2000, vec![0.698, 0.140, 0.073, 0.125]),
        ("Blade Runner", 1982, vec![0.379, 0.637, 0.011, 0.647]),
    ];

    for (title, year, embedding) in movies {
        app_handle
            .libsql()
            .execute(ExecuteOptions {
                connection_id: connection_id.clone(),
                sql: "INSERT INTO movies (title, year, embedding) VALUES (?, ?, vector32(?))"
                    .to_string(),
                params: Some(vec![
                    Value::Text(title.to_string()),
                    Value::Integer(year),
                    Value::vector32(embedding), // Using the helper function
                ]),
                named_params: None,
            })
            .await
            .map_err(|e| e.to_string())?;
    }

    // 创建向量索引
    app_handle
        .libsql()
        .create_vector_index(
            connection_id.clone(),
            "movies_idx".to_string(),
            "movies".to_string(),
            "embedding".to_string(),
            Some(vec!["metric=cosine".to_string()]), // Optional settings
        )
        .await
        .map_err(|e| e.to_string())?;

    Ok(format!(
        "Vector demo database created successfully with connection ID: {}",
        connection_id
    ))
}

#[tauri::command]
async fn vector_similarity_search(
    app_handle: tauri::AppHandle,
    connection_id: String,
) -> Result<String, String> {
    // 执行向量相似性搜索
    let query_vector = vec![0.064, 0.777, 0.661, 0.687];

    let results = app_handle
        .libsql()
        .vector_top_k(VectorTopKOptions {
            connection_id: connection_id.clone(),
            index_name: "movies_idx".to_string(),
            query_vector,
            k: 3,
            vector_type: Some(VectorType::Float32),
        })
        .await
        .map_err(|e| e.to_string())?;

    // 返回结果摘要
    Ok(format!("Found {} similar movies", results.rows.len()))
}

#[tauri::command]
async fn calculate_vector_distance(
    app_handle: tauri::AppHandle,
    connection_id: String,
) -> Result<f64, String> {
    // 计算两个向量之间的余弦距离
    let vector1 = Value::vector32(vec![0.800, 0.579, 0.481, 0.229]);
    let vector2 = Value::vector32(vec![0.406, 0.027, 0.378, 0.056]);

    app_handle
        .libsql()
        .vector_distance_cos(connection_id, vector1, vector2)
        .await
        .map_err(|e| e.to_string())
}

fn main() {
    tauri::Builder::default()
        .plugin(tauri_plugin_libsql::init())
        .invoke_handler(tauri::generate_handler![
            greet,
            create_demo_db,
            create_vector_demo,
            vector_similarity_search,
            calculate_vector_distance
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
